fix: guard undefined entity on the incoming-message handlers#2922
Conversation
|
This PR will not go through. Please rework:
Alternatively, this will return onto the stack of planned reworks and be done when I get to it. A. |
handleMessage and onZigbeeEvent run for every incoming zigbee message, bound
fire-and-forget on the herdsman 'message' event and the controller 'event'
event. resolveEntity() can return undefined for a message from a device that
does not resolve (unknown/leaving device, DB race), and neither path guarded it:
- handleMessage dereferenced data/entity (data.device.interviewState,
data.device || data.ieeeAddr, ...) without guarding undefined.
- onZigbeeEvent dereferenced entity.device at the top without guarding entity.
Since both handlers are async and their callers don't await them, the throw
became an unhandled promise rejection - fatal under compact mode.
- onZigbeeEvent guards the entity and returns early, after its debug line so an
unresolved message is still logged; the redundant `.device` half is dropped
(resolveEntity returns a structure with `.device` or undefined).
- handleMessage addresses data via `data?.` and uses `entity?.options ?? {}`
and `entity?.name`. resolveEntity self-catches and returns undefined,
callExtensionMethod guards each extension call, and event() dispatches via
emit, so no wrapping try/catch is needed.
- utils.entityData() is made null-safe (`name: e?.name`, the only field there
not already using optional chaining) so the debug line is safe for an
unresolved entity.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96ee9a8 to
0faac47
Compare
|
Reworked:
One related line in utils.js: entityData() had |
|
Thanks. |
Problem
The adapter occasionally crashes on incoming zigbee traffic (and under compact mode can take the controller with it) — part of the "randomly wobbly" class of failures. Both handlers that run for every incoming message dereference the resolved entity without guarding it, and
resolveEntity()can returnundefinedfor a message from a device that does not resolve (a device that is leaving/unknown, or a DB race). Both handlers are async and bound fire-and-forget (herdsmanmessage, controllerevent/msg), so the throw becomes an unhandled promise rejection.ZigbeeController.handleMessagebuildsoptions: entity.options || {}— the line just above already guardsentity &&, but this one dereferencesentity.optionsunconditionally →TypeError: Cannot read properties of undefinedon an unresolved entity.StatesController.onZigbeeEventdereferencesentity.deviceat the very top, before itstryblock.Fix
handleMessage: guard withentity?.options ?? {}and wrap the body in a top-leveltry/catch(log instead of crashing — it is the central message entry point).onZigbeeEvent: return early whenentity/entity.deviceis missing (an event for an unresolvable entity cannot be processed; everything below needs the device).No behaviour change for resolved entities. The missing guard is visible directly in the code (the preceding line guards
entity, this one does not;event()forwards the entity unconditionally), independent of reproducibility.Testing
node --checkpasses on both files.undefined-entity path is now handled instead of throwing.